package com.hy.service.impl;

import com.hy.bean.RespBean;
import com.hy.bean.SysDept;
import com.hy.dao.SysDeptDao;
import com.hy.dto.DeptDto;
import com.hy.service.DeptDervice;
import com.hy.utils.DBManager;
import com.hy.utils.LevelUtil;
import org.apache.commons.collections.CollectionUtils;
import com.google.common.base.Preconditions;

import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @Description:
 * @Author: zhangzhengwei2006
 * @Date: 2024-01-31 21:51
 *
 *
 */
public class DeptServiceimpl implements DeptDervice {
    //children
    private SysDeptDao deptDao = new SysDeptDao();

    @Override
    public RespBean save(SysDept dept) throws Exception {
        //算level值
        if (dept.getParent_id() != 0) {
            SysDept sysDept = deptDao.selectLeelById(dept.getParent_id());
            String level = sysDept.getLevel() + "." + sysDept.getId();
            dept.setLevel(level);
        }
        //时间
        //        SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        dept.setOperate_time(date);
        dept.setSeq(1);
        //        dept.setParent_id(sysDept.getId());
        int i = deptDao.insertDept(dept);
        if (i > 0) {
            return RespBean.success("添加成功");
        }
        return RespBean.success("添加失败");
    }

    @Override
    public List<Map<String, Object>> list() throws Exception {
        List<Map<String, Object>> sysDepts = deptDao.selectAllDept();//查询所有
        return sysDepts.stream().filter(m -> m.get("parent_id").equals(0)).peek((m) -> m.put("children", getChildrens(m, sysDepts))).collect(Collectors.toList());
    }

    private static List<Map<String, Object>> getChildrens(Map<String, Object> root, List<Map<String, Object>> all) {
        return all.stream().filter(m -> Objects.equals(m.get("parent_id"), root.get("id"))).peek((m) -> m.put("children", (getChildrens(m, all)))).collect(Collectors.toList());
    }

    public RespBean del(Integer id) throws Exception {
        List<SysDept> sysDeptList = new ArrayList<>();
        if (id != null) {
            sysDeptList = deptDao.selectByParentId(id);
        }
        if (!sysDeptList.isEmpty()) {
            for (int i = 0; i < sysDeptList.size(); i++) {
                deptDao.delectByid(sysDeptList.get(i).getId());
            }
        }
        Boolean b = deptDao.delectByid(id);
        if (b) {
            return RespBean.success("删除成功");
        }

        return RespBean.error("删除失败");
    }

    @Override
    public boolean updateDept(DeptDto deptDto) throws Exception {
        Connection conn = DBManager.getConn();
        try {
            conn.setAutoCommit(false);
            //1,根据id查询，待更新的部门是否存在，不存在抛出异常
            SysDept beforeSysDept = deptDao.selectById(conn, deptDto.getId());

            //google包中抛异常的
            Preconditions.checkNotNull(beforeSysDept, "待更新的部门不存在");

            //2, 查询部门名称是否重复，同一个层级下的部门名称不能重复。否则抛出异常
            //修改时， 查询重复部门的时候，需要传递 id值。
            boolean flag = deptDao.countByNameAndParentId(conn, deptDto.getParent_id(), deptDto.getName(), null);
            if (beforeSysDept.getSeq().equals(deptDto.getSeq()) || beforeSysDept.getStatus().equals(deptDto.getSeq())){//判断排序或状态是否发生改变
                if (flag) { //如果为true说明，同一个层级下部门名称相同，则抛出异常
                    throw new RuntimeException("同一个层级下部门名称相同");
                }
            }

            //3,准备修改的部门信息值
            SysDept afterSysDept = SysDept.builder().id(deptDto.getId()).name(deptDto.getName()).parent_id(deptDto.getParent_id())  //新的上级部门的id
                    .seq(deptDto.getSeq()).remark(deptDto.getRemark()).operator(deptDto.getOperator()).operate_ip(deptDto.getOperateIp()).build(); //记得最后调用build()方法

            //3.2 根据传递过来的 parentId (父级部门id)，查询该父级部门的 level  //parentId =>  12
            String level = deptDao.selectById(conn, deptDto.getParent_id()).getLevel();  // '0'

            //3.3 计算得到当前更新部门的level值
            afterSysDept.setLevel(LevelUtil.calculateLevel(level, deptDto.getParent_id())); // 0.12

            //4, 更新当前部门信息 以及 当前部门的子部门或子子部门的信息
            updateWithChild(conn, beforeSysDept, afterSysDept);

            boolean isCompleted = updateWithChild(conn, beforeSysDept, afterSysDept);

            if (isCompleted) {
                conn.commit();
                return true;
            } else {
                conn.rollback();
                return false;
            }
        } catch (Exception e) {
            conn.rollback();
            return false;
        }
    }

    /**
     * @param conn
     * @param before 更新前的部门信息
     * @param after  更新后的部门信息
     * @return 返回true 表示 更新成功， false表示更新失败
     * @throws Exception
     * 该方法用来完成更新部门信息(名字，层级，顺序，备注等信息) 和 该部门的 子部门 与 子子部门的层级
     * 注意要先更新子部门 或 子子部门的信息，再更新主部门的信息，否则可能会有问题
     */
    public boolean updateWithChild(Connection conn, SysDept before, SysDept after) throws Exception {
        //判断是否更新子部门
        //取出更新前的旧的level 和 要更新的新的level
        String oldLevel = before.getLevel();
        String newLevel = after.getLevel();

        //如果level不一致时，才做子部门或子子部门的更新。 如果一致，就不需要做子部门的更新
        if (!after.getLevel().equals(before.getLevel())) {
            //取出当前要更新部门的子部门，注意：根据 oldLevel 查询出来的子部门数据可能有问题。后面要进一步排除
            List<SysDept> childSysDeptList = deptDao.selectChildDeptListByLevel(conn, oldLevel);
            //            System.out.println(childSysDeptList);

            //合格的子部门或子子部门的数据放入到这个集合当中
            List<SysDept> childSysDeptList2 = new ArrayList<>();

            //判断是否为空，或是集合里面的元素是否为null，不为空则返回true
            if (CollectionUtils.isNotEmpty(childSysDeptList)) {
                //不为空，则遍历子部门集合
                for (SysDept sysDept : childSysDeptList) {
                    //取出这个子部门的level
                    String childLevel = sysDept.getLevel();
                    //这里我们还要进行进一步的判断筛选，因为 查询 出来的 数据，有别的子部门的数据。
                    //因为我们的子部门就是根据旧的oldLevel+"."来查询的
                    if (childLevel.indexOf(oldLevel + "." + before.getId()) == 0) {
                        //修改子部门 或 子子部门的level
                        childLevel = newLevel + childLevel.substring(oldLevel.length());
                        //更新子部门或子子部门的level
                        sysDept.setLevel(childLevel);
                        //将要更新的部门添加到 新集合当中
                        childSysDeptList2.add(sysDept);
                    }
                }
                //                System.out.println(childSysDeptList2);
                //批量更新子部门或子子部门的level值
                int count = deptDao.batchUpdateLevel(conn, childSysDeptList2);
            }
        }
        //最后更新当前部门信息 isCompleted = flag;
        //1，根据id值更新当前部门的信息
        after.setOperate_time(new Date());
        boolean flag = deptDao.updateById(conn, after);

        return flag;
    }
}
